package com.vertxsample.samples.core.web

import io.vertx.circuitbreaker.CircuitBreaker
import io.vertx.circuitbreaker.CircuitBreakerOptions
import io.vertx.core.Handler
import io.vertx.core.Vertx
import io.vertx.ext.consul.ConsulClient
import io.vertx.ext.web.RoutingContext
import io.vertx.ext.web.client.WebClient
import org.apache.logging.log4j.LogManager
import kotlin.random.Random
//网关访问
class GatewayHandler (val vertx : Vertx, val consulClient: ConsulClient): Handler<RoutingContext> {
    val logger = LogManager.getLogger(GatewayHandler::class.java!!.getName())
    override fun handle(routingContext: RoutingContext?) {
        //服务名
        val nodeServerName = routingContext!!.request().getParam("nodeServerName")
        val uri =routingContext!!.request().uri()
        logger.info("visit:"+uri)
        consulClient.healthServiceNodes(nodeServerName,true, { res ->
            if (res.succeeded()) {
                val nodeList =res.result().list
                logger.info("found ${nodeList.size} services")
                logger.info("consul state index: ${res.result().index}")


                for (node in nodeList) {
                    logger.info("Service node: ${node.node.name}")
                    logger.info("Service address: ${node.node.address}")
                    logger.info("Service port: ${node.service.port}")
                }


                //随机选择节点
                val selectedNodeIndex= Math.abs(Random.nextInt() % nodeList.size)
                val selectedNode =nodeList[selectedNodeIndex]

                var selectedUri = uri.substring(("/gateway/"+nodeServerName).length)
                logger.info("redirect to visit:"+selectedUri)


                //限流器
                var breaker = CircuitBreaker.create("gateway-circuit-breaker", vertx, CircuitBreakerOptions(
                ).setMaxFailures(5).setTimeout(5000L).setFallbackOnFailure(true).setResetTimeout(10000L)
                )



                breaker.execute<Any>({ future ->
                    // some code executing with the breaker
                    // the code reports failures or success on the given future.
                    // if this future is marked as failed, the breaker increased the
                    // number of failures
                    //访问服务节点
                    var webclient= WebClient.create(vertx).request(routingContext.request().method(), selectedNode.service.port,
                        selectedNode.node.address ,selectedUri)

                    val gatewayHeaders=routingContext!!.request().headers();
                    gatewayHeaders.forEach { h->
                        webclient =webclient.putHeader(h.key,h.value)
                    }

                    webclient.send({ ar ->
                        if (ar.succeeded()) {
                            // Obtain response
                            val response = ar.result()
                            routingContext.response() .putHeader("content-type","text/html;charset=utf-8").end( response.bodyAsString("UTF-8"),"UTF-8")
                            logger.info("Received response with status code:${response.statusCode()}")
                        } else {
                            logger.error("Something went wrong ${ar.cause().localizedMessage}",ar.cause())
                        }
                        //限流器报告,否则报超时
                        future.complete()
                    })

                }).setHandler({ ar ->
                    // Get the operation result.
                    if(ar.failed()){
                        logger.error("",ar.cause())
                    }
                })
            } else {
                logger.error("",res.cause())
            }
        })
    }

}